/*
 * Copyright (C) 2015 The Sven Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cc.core.util;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.List;

/**
 * 作者：helloTan on 15/7/14 14:29
 * 邮箱：hellotanm@gmail.com
 */
public class NetUtil {

    public static NetworkInfo.State getNetState(Context context) {

        ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo.State state = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
        if (NetworkInfo.State.CONNECTED == state) {
            return state;
        }

        state = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();

        return state;
    }

    public static class WifiUtil {

        public enum SEC_TYPE { OPEN, WEP, WAP }

        private Context context;

        private WifiManager wifi;

        public WifiUtil(Context context) {
            this.context = context;
            this.wifi = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
        }

        public boolean isConnect() {

            ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkInfo.State state = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
            return NetworkInfo.State.CONNECTED == state;

        }

        public String getLocalIpAddress() {
            try {
                for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                    NetworkInterface intf = en.nextElement();
                    for (Enumeration<InetAddress> enumIpAddr = intf
                            .getInetAddresses(); enumIpAddr.hasMoreElements();) {
                        InetAddress inetAddress = enumIpAddr.nextElement();
                        if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) {
                            return inetAddress.getHostAddress();
                        }
                    }
                }
            } catch (SocketException ex) {
                ex.printStackTrace();
            }

            int ipInt = this.wifi.getConnectionInfo().getIpAddress();

            StringBuilder sb = new StringBuilder();
            sb.append(ipInt & 0xFF).append(".");
            sb.append((ipInt >> 8) & 0xFF).append(".");
            sb.append((ipInt >> 16) & 0xFF).append(".");
            sb.append((ipInt >> 24) & 0xFF);

            return sb.toString();
        }

        public String getLocalMacAddress() {

            WifiInfo info = this.wifi.getConnectionInfo();
            return info.getMacAddress();
        }

        public int addWifi(String ssid, String passCode, SEC_TYPE type) {

            ssid = "\"" + ssid + "\"";
            passCode = "\"".concat(passCode).concat("\"");

            LogUtil.e("ssid " + ssid + "\tcode "+passCode);

            List<WifiConfiguration> confs = this.wifi.getConfiguredNetworks();

            if (confs != null) {
                for (WifiConfiguration conf : confs) {
                    if (conf.SSID.equals(ssid)) {
                        this.wifi.removeNetwork(conf.networkId);
                    }
                }
            }

            WifiConfiguration wifiConfig = new WifiConfiguration();

            wifiConfig.SSID = ssid;
            wifiConfig.status = WifiConfiguration.Status.DISABLED;
            wifiConfig.priority = 40;

            switch (type) {
                // Dependent on the security type of the selected network
                // we set the security settings for the configuration
                case OPEN:
                    // No security
                    wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                    wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                    wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                    wifiConfig.allowedAuthAlgorithms.clear();
                    wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                    wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                    break;

                case WAP:
                    //WPA/WPA2 Security
                    wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                    wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                    wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
                    wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                    wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                    wifiConfig.preSharedKey = passCode;
                    break;

                case WEP:
                    // WEP Security
                    wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                    wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                    wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                    wifiConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
                    wifiConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
                    wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                    wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
                    wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);

                    if (getHexKey(passCode)) wifiConfig.wepKeys[0] = passCode;
                    else wifiConfig.wepKeys[0] = passCode;
                    wifiConfig.wepTxKeyIndex = 0;
                    break;
            }

            // Finally we add the new configuration to the managed list of networks
            return this.wifi.addNetwork(wifiConfig);
        }

        /**
         * WEP has two kinds of password, a hex value that specifies the key or
         * a character string used to generate the real hex. This checks what kind of
         * password has been supplied. The checks correspond to WEP40, WEP104 & WEP232
         * @param s code
         * @return f
         */
        private static boolean getHexKey(String s) {
            if (s == null) {
                return false;
            }

            int len = s.length();
            if (len != 10 && len != 26 && len != 58) {
                return false;
            }

            for (int i = 0; i < len; ++i) {
                char c = s.charAt(i);
                if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
                    continue;
                }
                return false;
            }
            return true;
        }

        public boolean openAP(String ssid, String passCode) throws Exception {

            if (this.wifi.isWifiEnabled()) this.wifi.setWifiEnabled(false);

            WifiConfiguration apConfig = new WifiConfiguration();

            apConfig.SSID = ssid;

            apConfig.preSharedKey = passCode;

            Method setWifiApEnabled = wifi.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);

            return (Boolean)setWifiApEnabled.invoke(wifi, apConfig, true);
        }

        public boolean closeAP() throws Exception {

            Method getWifiApConfiguration = this.wifi.getClass().getMethod("getWifiApConfiguration");

            WifiConfiguration apConfig = (WifiConfiguration)getWifiApConfiguration.invoke(wifi);

            Method setWifiApEnabled = wifi.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);

            boolean next = (Boolean)setWifiApEnabled.invoke(wifi, apConfig, false);

            if (!this.wifi.isWifiEnabled()) this.wifi.setWifiEnabled(true);

            return next;
        }
    }
}
